package utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Vector;

import main.Instance;
import main.Instance.Weight;
import main.Solution;

public class IOUtils {

	
	public static final String NO_SOL_MSG = "UNSAT";
	public static final String lineSeperator = System.getProperty("line.separator");

	public static Instance loadInstanceFile(String filename){
		Instance instance = null;
		try{
			BufferedReader br = new BufferedReader(new FileReader(filename));
			
			// Read number of vertices
			String line = br.readLine();
			int optimalSolution = -1;
			while (instance == null){
				
				if (line.trim().startsWith("%")){ // Read optimal solution size
					String optimal = line.substring(line.indexOf("optimal="), line.indexOf("time="));
					optimal = optimal.substring(optimal.indexOf("=")+1);
					optimalSolution = Integer.parseInt(optimal.trim());
					line = br.readLine();
				}
				else{
					instance = new Instance(Integer.parseInt(line.trim()));
					instance.setOptimalSolution(optimalSolution);
				}
					
			}
			while ((line = br.readLine())!=null){
				if (line.trim().startsWith("%")) // Skip comment lines
					continue;
				
				String[] tokens = line.split(" ");
				int from = Integer.parseInt(tokens[0].trim());
				int to = Integer.parseInt(tokens[1].trim());
				int weight = Integer.parseInt(tokens[2].trim());
				Weight w = weight == 2?Weight.LONG:Weight.SHORT;
				instance.addEdge(from, to, w);
			}
		}
		catch(IOException ioex){
			ioex.printStackTrace();
		}
		return instance;
	}
	
	public static void writeCnfToFile(Vector<int[]> cnf, int literalCount, String cnfFileName) {
		FileWriter fw =null;
		try {
			File f = new File(cnfFileName);
			fw = new FileWriter(f);
			fw.write("p cnf " + literalCount + " " + cnf.size() +"\n");
			cnfToFileWriter(cnf, fw);
			
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			if (fw != null){
				try {
					fw.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	public static void cnfToFileWriter(Vector<int[]> cnf, FileWriter fw) throws IOException {
		
			Iterator<int[]> it = cnf.iterator();
			while (it.hasNext()){
				int[] clause = it.next();
				String clauseString = "";
				for (int i = 0 ; i < clause.length; i++){
					clauseString += clause[i] + " "; 
				}
				fw.write(clauseString + "0");
				fw.write(lineSeperator);
			}
			
			fw.flush();
	}
	
	
	public static void generateScriptFile(String fileName, Vector<int[]> cnf, int[] sumBits) {
		try {
			
			String lineSeperator = IOUtils.lineSeperator;
			File res = new File(fileName);
			
			FileWriter fw =null;
			try {
				fw = new FileWriter(res);
				fw.write("cnf" + lineSeperator);
				IOUtils.cnfToFileWriter(cnf, fw);
				
				fw.write("end" + lineSeperator);
				String mode = "binary";
				
				fw.write("minimize " + mode +" ");
				for (int i = 0; i < sumBits.length; i++) {
					fw.write(sumBits[i] + " ");
				}
								
				fw.write("0" + lineSeperator);
				fw.write("kill" + lineSeperator);
				fw.flush();
				
			} catch (IOException e) {
				e.printStackTrace();
			}finally{
				if (fw != null){
					try {
						fw.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void generateSolFile(String solFilePath, Solution sol) {
		FileWriter fw =null;
		try {
			File f = new File(solFilePath);
			fw = new FileWriter(f);

			fw.write(sol.getNumOfStrong() + lineSeperator);
			
			for (Entry<Integer, Boolean> node : sol.getNodes().entrySet()){
				int nodeNumber = node.getKey();
				boolean isStrong = node.getValue();
				int transmitter = isStrong ? 2 : 1;
				
				String line = Integer.toString(nodeNumber) + " " + Integer.toString(transmitter)  ;
				fw.write(line + lineSeperator);
			}
			fw.flush();
			
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			if (fw != null){
				try {
					fw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public static void generateNoSolFile(String solFilePath) {
		FileWriter fw =null;
		try {
			File f = new File(solFilePath);
			fw = new FileWriter(f);

			fw.write(NO_SOL_MSG);
			
			fw.flush();
			
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			if (fw != null){
				try {
					fw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public static void generateDotFile(String dotFilePath, Map<Pair<Integer, Integer>, Weight> edges, Solution sol) {
		FileWriter fw =null;
		try {
			File f = new File(dotFilePath);
			fw = new FileWriter(f);
			fw.write("digraph G{"+lineSeperator);
			fw.write("edge ["+lineSeperator);
			fw.write("arrowhead=\"none\""+lineSeperator);
			fw.write("];"+lineSeperator);
			for (Entry<Pair<Integer, Integer>, Weight> edge : edges.entrySet()) {
				String color = "blue";
				if (edge.getValue().equals(Weight.LONG)){
					color = "red";
				}
				Pair<Integer, Integer> p = edge.getKey();
				fw.write(p.first+" -> "+p.second+"[dir=none color=\"" + color + "\"];"+lineSeperator);
			}
			Set<Entry<Integer, Boolean>> nodes = sol.getNodes().entrySet();
			for (Entry<Integer, Boolean> node : nodes) {
				if (node.getValue()){
					fw.write(node.getKey() + " [style=filled, fillcolor=red]"  + lineSeperator);
				}else{
					fw.write(node.getKey() + " [style=filled, fillcolor=blue]"  + lineSeperator);
				}
			}
			
			
			fw.write("}"+lineSeperator);
			fw.flush();
			
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			if (fw != null){
				try {
					fw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}